package com.boyinet.imesh2json.fx.controller

import com.boyinet.imesh2json.bean.DataMap
import com.boyinet.imesh2json.bean.Template
import com.boyinet.imesh2json.common.UiUtil
import com.boyinet.imesh2json.fx.view.MapDialogView
import com.boyinet.imesh2json.viewmodel.TemplateViewModel
import de.felixroske.jfxsupport.AbstractJavaFxApplicationSupport
import de.felixroske.jfxsupport.FXMLController
import javafx.event.EventHandler
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.control.*
import javafx.scene.control.cell.PropertyValueFactory
import javafx.scene.control.cell.TextFieldListCell
import javafx.scene.input.MouseButton
import javafx.scene.layout.AnchorPane
import javafx.stage.Modality
import javafx.util.StringConverter
import jfxtras.styles.jmetro.FlatAlert
import jfxtras.styles.jmetro.JMetro
import org.controlsfx.control.ToggleSwitch
import org.springframework.beans.factory.annotation.Autowired
import java.net.URL
import java.util.*

@FXMLController
class TemplateViewController : Initializable {

    @FXML
    lateinit var root: AnchorPane

    @FXML
    lateinit var templateList: ListView<Template>

    @FXML
    lateinit var dataTable: TableView<DataMap>

    @FXML
    lateinit var idCol: TableColumn<DataMap, Int>

    @FXML
    lateinit var nodeCol: TableColumn<DataMap, Int>

    @FXML
    lateinit var partCol: TableColumn<DataMap, Int>

    @FXML
    lateinit var indexCol: TableColumn<DataMap, Int>

    @FXML
    lateinit var fieldCol: TableColumn<DataMap, String>

    @FXML
    lateinit var sn: TextField

    @FXML
    lateinit var signalStrength: TextField

    @FXML
    lateinit var powerSource: TextField

    @FXML
    lateinit var powerSupply: TextField

    @FXML
    lateinit var batteryPower: TextField

    @FXML
    lateinit var alarmBit: TextField

    @FXML
    lateinit var originalValue: ToggleSwitch

    @FXML
    lateinit var fields: TextField

    @FXML
    lateinit var decimalPlaces: TextField

    @FXML
    lateinit var unit: TextField

    @FXML
    lateinit var sensorType: TextField


    lateinit var settingContextMenu: ContextMenu

    @Autowired
    lateinit var templateViewModel: TemplateViewModel

    @FXML
    lateinit var delButton: Button

    @FXML
    lateinit var okButton: Button

    @FXML
    lateinit var applyButton: Button

    override fun initialize(location: URL?, resources: ResourceBundle?) {

        val jMetro = JMetro()
        jMetro.parent = root

        renderContextMenu()

        renderListView()

        if (templateList.items.size > 0) {
            templateViewModel.showInfo(0)
        } else {
            templateViewModel.showEmpty()
        }

        bindColumnProperty()

        bindFormProperty()

        bindButtonStatusProperty()

        renderTableView()


    }

    private fun bindButtonStatusProperty() {
        delButton.disableProperty().bindBidirectional(templateViewModel.disableDel)
        okButton.disableProperty().bindBidirectional(templateViewModel.disableOk)
        applyButton.disableProperty().bindBidirectional(templateViewModel.disableApply)
    }

    private fun renderTableView() {
        with(dataTable) {
            items = templateViewModel.dataMapsViewModel.dataMaps

            setOnMouseClicked {
                if (it.button == MouseButton.SECONDARY) {
                    settingContextMenu.show(dataTable, it.screenX, it.screenY)
                } else if (it.button == MouseButton.PRIMARY) {
                    settingContextMenu.hide()
                }
            }
        }
    }

    private fun renderListView() {
        with(templateList) {

            items = templateViewModel.lists
            cellFactory = TextFieldListCell.forListView(
                object : StringConverter<Template>() {
                    override fun toString(`object`: Template?): String {
                        return `object`?.name!!
                    }

                    override fun fromString(string: String?): Template {
                        templateViewModel.current.name.value = string
                        return templateViewModel.current.export()
                    }
                })

            isEditable = true

            onEditStart = EventHandler {

            }

            onEditCommit = EventHandler {
                templateViewModel.current.name.value = it.newValue.name
                templateViewModel.update(it.index)
            }

            selectionModel.selectedIndexProperty().addListener { _, oldValue, newValue ->
                if (newValue == -1) {
                    return@addListener
                }
                if (oldValue !== newValue) {
                    templateViewModel.showInfo(newValue.toInt())
                }
            }
        }
    }

    private fun renderContextMenu() {
        settingContextMenu = ContextMenu()
        val addItem = MenuItem("添加映射")
        val editItem = MenuItem("编辑映射")
        val deleteItem = MenuItem("删除映射")

        addItem.setOnAction {
            with(templateViewModel.dataMapsViewModel) {
                current.clear(this.currentTemplateId!!)
                update = false
            }
            UiUtil.showModal(MapDialogView::class.java, Modality.WINDOW_MODAL, "新增映射")

        }

        editItem.setOnAction {
            if (dataTable.selectionModel.isEmpty) {
                val flatAlert = FlatAlert(Alert.AlertType.WARNING)
                flatAlert.contentText = "请先选择要编辑的节点"
                JMetro().scene = flatAlert.dialogPane.scene
                flatAlert.show()
                return@setOnAction
            }
            with(templateViewModel.dataMapsViewModel) {
                index = dataTable.selectionModel.selectedIndex
                current.fill(dataTable.selectionModel.selectedItem)
                update = true
            }
            UiUtil.showModal(MapDialogView::class.java, Modality.WINDOW_MODAL, "编辑映射")
        }

        deleteItem.setOnAction {
            if (dataTable.selectionModel.isEmpty) {
                val flatAlert = FlatAlert(Alert.AlertType.WARNING)
                flatAlert.contentText = "请先选择要删除的节点"
                JMetro().scene = flatAlert.dialogPane.scene
                flatAlert.show()
                return@setOnAction
            }
            templateViewModel.dataMapsViewModel.delete(dataTable.selectionModel.selectedItem)
        }

        settingContextMenu.items.addAll(listOf(addItem, editItem, deleteItem))
    }

    private fun bindColumnProperty() {
        idCol.cellValueFactory = PropertyValueFactory("id")
        nodeCol.cellValueFactory = PropertyValueFactory("node")
        partCol.cellValueFactory = PropertyValueFactory("part")
        indexCol.cellValueFactory = PropertyValueFactory("index")
        fieldCol.cellValueFactory = PropertyValueFactory("field")
    }

    private fun bindFormProperty() {
        sn.textProperty().bindBidirectional(templateViewModel.current.sn)
        signalStrength.textProperty().bindBidirectional(templateViewModel.current.signalStrength)
        powerSource.textProperty().bindBidirectional(templateViewModel.current.powerSource)
        powerSupply.textProperty().bindBidirectional(templateViewModel.current.powerSupply)
        batteryPower.textProperty().bindBidirectional(templateViewModel.current.batteryPower)
        alarmBit.textProperty().bindBidirectional(templateViewModel.current.alarmBit)
        originalValue.selectedProperty().bindBidirectional(templateViewModel.current.originalValue)

        fields.textProperty().bindBidirectional(templateViewModel.current.fields)
        decimalPlaces.textProperty().bindBidirectional(templateViewModel.current.decimalPlaces)
        unit.textProperty().bindBidirectional(templateViewModel.current.unit)
        sensorType.textProperty().bindBidirectional(templateViewModel.current.sensorType)
    }

    fun add() {
        templateViewModel.insert()
        templateList.selectionModel.select(templateViewModel.originalIndex + 1)
    }

    fun del() {
        templateViewModel.delete()
        if (templateViewModel.lists.isEmpty()) {
            templateList.selectionModel.clearSelection()
            templateViewModel.showEmpty()
        } else {
            templateList.selectionModel.select(0)
            templateViewModel.showInfo(0)
        }
    }

    fun ok() {
        apply()
        root.scene.window.hide()
    }

    fun apply() {
        templateViewModel.save()
    }

    fun cancel() {
        templateViewModel.revert()
        root.scene.window.hide()
    }
}